package com.wulis.config.security;

import static com.wulis.common.constant.GlobalConstant.ADMINISTRATOR;
import static com.wulis.common.constant.GlobalConstant.ROLE_MENU_BUTTON;

import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.wulis.common.model.enums.EnableStateEnum;
import com.wulis.common.utils.AuthUserUtil;
import com.wulis.provider.authority.model.bo.RoleBo;
import com.wulis.provider.authority.service.RoleService;

/**
 * @author WuliBao
 */
@Component("api")
public class AuthorityService {
    
    @Resource
    private RoleService roleService;
    
    @Resource
    private RedisTemplate<String, RoleBo> redisTemplate;
    
    /**
     * 验证用户是否具备某权限
     *
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    public boolean hasPermission(String permission) {
        // 获取当前用户信息
        AuthUserDetails authUserDetails = AuthUserUtil.getDetails();
        // 如果是超级管理员则直接放行
        if (ADMINISTRATOR.equals(authUserDetails.getAccountId())) {
            return true;
        }
        if (CollectionUtils.isEmpty(authUserDetails.getRoles())) {
            return false;
        }
        // 判断redis中是否存在角色权限信息
        Boolean key = redisTemplate.hasKey(ROLE_MENU_BUTTON);
        // 如果不存在则查询数据库加入到缓存中
        if (key != null && !key) {
            // 双重检测同步锁，防止Redis缓存穿透
            synchronized (this) {
                key = redisTemplate.hasKey(ROLE_MENU_BUTTON);
                if (key != null && !key) {
                    // 查询全部角色对应的菜单按钮权限集合
                    Set<RoleBo> roles = roleService.queryAllRoleButton();
                    // 存入redis
                    RoleBo[] roleArray = roles.toArray(new RoleBo[0]);
                    redisTemplate.opsForSet().add(ROLE_MENU_BUTTON, roleArray);
                }
            }
        }
        // 查询redis中的角色权限集合
        Set<RoleBo> roles = redisTemplate.opsForSet().members(ROLE_MENU_BUTTON);
        if (roles == null) {
            roles = new HashSet<>();
        }
        // 获取用户所具备的接口权限
        Set<Long> roleIds =
            authUserDetails.getRoles().stream().map(AuthUserDetails.Role::getRoleId).collect(Collectors.toSet());
        Set<String> permissions = new HashSet<>();
        roles.forEach(role -> {
            if (roleIds.contains(role.getId())) {
                permissions.addAll(role.getButtons()
                    .stream()
                    .filter(button -> EnableStateEnum.IS_ENABLED.value().equals(button.getEnable()))
                    .map(RoleBo.Button::getPermissionMark)
                    .collect(Collectors.toSet()));
            }
        });
        // 校验是否包含该接口权限
        return hasPermissions(permissions, permission);
    }
    
    /**
     * 判断是否包含权限
     *
     * @param permissions 权限列表
     * @param permission 权限字符串
     * @return 用户是否具备某权限
     */
    private boolean hasPermissions(Set<String> permissions, String permission) {
        return permissions.contains(permission);
    }
}
